/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.udt.designtime.manager.services;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.collection.CommonDtmCollection;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.designtime.api.operation.CommonDetermination;
import com.inspur.edp.cef.designtime.api.operation.CommonOperation;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataHeader;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import com.inspur.edp.lcm.metadata.api.service.RefCommonService;
import com.inspur.edp.lcm.metadata.spi.IMetadataReferenceManager;
import com.inspur.edp.udt.designtime.api.entity.ComplexDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.UnifiedDataTypeDef;
import com.inspur.edp.udt.designtime.api.entity.element.UdtElement;
import com.inspur.edp.udt.designtime.api.entity.validation.ValidationInfo;
import com.inspur.edp.udt.designtime.api.utils.UdtUtils;
import com.inspur.edp.udt.designtime.manager.udtmanagerexception.UdtManagerException;
import io.iec.edp.caf.commons.exception.ExceptionLevel;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.ArrayList;
import java.util.List;

public class MetadataReferenceService implements IMetadataReferenceManager {

  private static String ERRORCODE = "MetadataReferenceService";

  /**
   * 获取元数据依赖集合
   * @param metadata
   * @return
   */
  @Override
  public List<MetadataReference> getConstraint(GspMetadata metadata) {
    if (metadata.getRefs() != null) {
      metadata.getRefs().clear();
    }
    buildMetadataReference(metadata);
    List<MetadataReference> list = new ArrayList<>();
    if (metadata.getRefs() != null && metadata.getRefs().size() > 0) {
      for (MetadataReference item : metadata.getRefs()) {
        list.add(item);
      }
    }
    return list;
  }

  private void buildMetadataReference(GspMetadata metadata) {
    if (metadata.getRefs() == null) {
      metadata.setRefs(new ArrayList<MetadataReference>());
    }

    MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
    UnifiedDataTypeDef udt = (UnifiedDataTypeDef) metadata.getContent();

    if (udt instanceof SimpleDataTypeDef) {
      buildSimpleDataTypeDefReference((SimpleDataTypeDef) udt, metadata, metadataService);
    } else if (udt instanceof ComplexDataTypeDef) {
      buildComplexDataTypeDefReference((ComplexDataTypeDef) udt, metadata, metadataService);
    } else {
      throw new UdtManagerException("", ERRORCODE, "无对应的udt类型，详细请见内部异常。", null, ExceptionLevel.Error, false);
    }
  }

  private void buildComplexDataTypeDefReference(ComplexDataTypeDef cUdt, GspMetadata metadata,
      MetadataService metadataService) {

    // ① 字段
    if (cUdt.getElements() != null && cUdt.getElements().size() > 0) {
      for (IGspCommonField ele : cUdt.getElements()) {
        dealElementReference((UdtElement) ele, metadata, metadataService);
      }
    }
    // ② val
    if (cUdt.getValidations() != null && cUdt.getValidations().size() > 0) {
      for (ValidationInfo val : cUdt.getValidations()) {
        buildUdtValidationInfoReference(val, metadata, metadataService);
      }
    }
    // ③ dtm
    DealCommonDtmCollection(cUdt.getDtmAfterCreate(), metadata, metadataService);
    DealCommonDtmCollection(cUdt.getDtmAfterModify(), metadata, metadataService);
    DealCommonDtmCollection(cUdt.getDtmBeforeSave(), metadata, metadataService);
  }

  private void DealCommonDtmCollection(CommonDtmCollection dtms, GspMetadata metadata,
      MetadataService metadataService) {
    if (dtms != null && dtms.getCount() > 0) {
      for (CommonDetermination dtm : dtms) {
        BuildCommonOpReference(dtm, metadata, metadataService);
      }
    }
  }

  public void BuildCommonOpReference(CommonOperation operation, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(operation.getComponentId(), metadata, metadataService);
  }


  private void dealElementReference(UdtElement element, GspMetadata metadata,
      MetadataService metadataService) {

  }

  private void buildSimpleDataTypeDefReference(SimpleDataTypeDef sUdt, GspMetadata metadata,
      MetadataService metadataService) {
    // ① 关联be
    if (sUdt.getObjectType() == GspElementObjectType.Association) {
      if (sUdt.getChildAssociations() != null && sUdt.getChildAssociations().size() > 0) {
        for (GspAssociation asso : sUdt.getChildAssociations()) {
          buildAssociationReference(asso, metadata, metadataService);
        }
      }
    }

    // ② val
    if (sUdt.getValidations() != null && sUdt.getValidations().size() > 0) {
      for (ValidationInfo val : sUdt.getValidations()) {
        buildUdtValidationInfoReference(val, metadata, metadataService);
      }
    }
  }

  private void buildUdtValidationInfoReference(ValidationInfo valInfo, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(valInfo.getCmpId(), metadata, metadataService);
  }

  private void buildAssociationReference(GspAssociation asso, GspMetadata metadata,
      MetadataService metadataService) {
    buildReference(asso.getRefModelID(), metadata, metadataService);

  }

  private void buildReference(String refMetadataId, GspMetadata metadata,
      MetadataService metadataService) {
    if (UdtUtils.checkNull(refMetadataId)) {
      return;
    }
    if (metadata.getRefs().stream()
        .anyMatch(item -> item.getDependentMetadata().getId().equals(refMetadataId))) {
      return;
    }

    RefCommonService refService = SpringBeanUtils.getBean(RefCommonService.class);
    GspMetadata refMetaData = refService.getRefMetadata(refMetadataId);
    if (refMetaData == null) {
      throw new RuntimeException("未找到关联的元数据，请确认！");
    }

    MetadataReference reference = new MetadataReference() {
      {
        setMetadata(metadata.getHeader());
        setDependentMetadata(refMetaData.getHeader());
      }
    };
    metadata.getRefs().add(reference);
  }

}
